package com.ruoyi.coal.modules.coalpile.controller;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.ruoyi.coal.common.utils.R;
import com.ruoyi.coal.modules.coalpile.domain.CpCoalsaveUses;
import com.ruoyi.coal.modules.coalpile.domain.ResultData;
import com.ruoyi.coal.modules.coalpile.domain.vo.LineChartVo;
import com.ruoyi.coal.modules.coalpile.domain.vo.resultVo;
import com.ruoyi.coal.modules.coalpile.domain.vo.statisticsVo;
import com.ruoyi.coal.modules.coalpile.mapper.CpCoalStatisticsDao;
import com.ruoyi.coal.modules.coalpile.service.CpCoalStatisticsService;
import com.ruoyi.common.annotation.DataSource;
import com.ruoyi.common.enums.DataSourceType;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Api(tags = {"煤场统计"})
@RequestMapping({"/coal"})
@DataSource(value = DataSourceType.SLAVE)
public class CoalStatisticsController {
  @Autowired
  private CpCoalStatisticsService cpCoalStatisticsService;

  @Autowired
  private CpCoalStatisticsDao cpCoalStatisticsDao;

  @ApiOperation(value = "存煤", notes = "存煤,每天只能存一次")
  @PostMapping({"/saveOrUpdateCoal"})
  public R saveOrUpdateCoal(@RequestBody CpCoalsaveUses cpCoalsaveUses) {
//    cpCoalsaveUses.setName(ShiroUtils.getUserEntity().getUsername());
    cpCoalsaveUses.setTime(new Date());
    QueryWrapper<CpCoalsaveUses> queryWrapper = new QueryWrapper();
    queryWrapper.eq("name", cpCoalsaveUses.getName());
    queryWrapper.eq("yard_id", Integer.valueOf(cpCoalsaveUses.getYardId()));
    queryWrapper.eq("type", cpCoalsaveUses.getType());
    if ("0".equals(cpCoalsaveUses.getType()) || "1".equals(cpCoalsaveUses.getType())) {
      LocalDate today = LocalDate.now();
      Date startDate = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
      Date endDate = Date.from(today.atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant());
      queryWrapper.between("time", startDate, endDate);
    }
    CpCoalsaveUses existingRecord = (CpCoalsaveUses)this.cpCoalStatisticsService.getOne((Wrapper)queryWrapper);
    if (existingRecord != null) {
      cpCoalsaveUses.setId(existingRecord.getId());
      boolean updateResult = this.cpCoalStatisticsService.updateById(cpCoalsaveUses);
      if (updateResult)
        return R.ok("计划已更新");
      return R.error("计划更新失败");
    }
    boolean saveResult = this.cpCoalStatisticsService.save(cpCoalsaveUses);
    if (saveResult)
      return R.ok("新计划已添加");
    return R.error("添加新计划失败");
  }

  @PostMapping({"/getHistorySave"})
  public CpCoalsaveUses getHistorySave(@RequestBody statisticsVo statisticsVo1) {
    QueryWrapper queryWrapper = new QueryWrapper();
    queryWrapper.eq("yard_id", Integer.valueOf(statisticsVo1.getYardId()));
    queryWrapper.eq("type", "0");
    queryWrapper.orderByDesc("time");
    List<CpCoalsaveUses> list = this.cpCoalStatisticsService.list((Wrapper)queryWrapper);
    if (list != null)
      return list.get(0);
    return null;
  }

  @PostMapping({"/getHistoryUses"})
  public CpCoalsaveUses getHistoryUses(@RequestBody statisticsVo statisticsVo1) {
    QueryWrapper queryWrapper = new QueryWrapper();
    queryWrapper.eq("yard_id", Integer.valueOf(statisticsVo1.getYardId()));
    queryWrapper.eq("type", "1");
    queryWrapper.orderByDesc("time");
    List<CpCoalsaveUses> list = this.cpCoalStatisticsService.list((Wrapper)queryWrapper);
    if (list != null)
      return list.get(0);
    return null;
  }

  @ApiOperation(value = "统计实际", notes = "统计预计")
  @PostMapping({"/listActual"})
  public List<ResultData> getCoalsaveUsesData(@RequestBody statisticsVo statisticsVo1) {
    QueryWrapper<CpCoalsaveUses> queryWrapper = new QueryWrapper();
    queryWrapper.eq("yard_id", Integer.valueOf(statisticsVo1.getYardId()));
    List<CpCoalsaveUses> cpCoalsaveUsesList = this.cpCoalStatisticsService.list((Wrapper)queryWrapper);
    LocalDate today = LocalDate.now();
    int currentYear = today.getYear();
    Month currentMonth = today.getMonth();
    int currentDay = today.getDayOfMonth();
    List<ResultData> totalResults = new ArrayList<>();
    Map<Integer, Double> yearlyInboundCoal = (Map<Integer, Double>)cpCoalsaveUsesList.stream().filter(usage -> ("2".equals(usage.getType()) && usage.toLocalDate().getYear() == currentYear)).collect(Collectors.groupingBy(usage -> Integer.valueOf(usage.toLocalDate().getYear()),

          Collectors.summingDouble(CpCoalsaveUses::getNumber)));
    if (!yearlyInboundCoal.isEmpty()) {
      List<resultVo> yearlyInbound = new ArrayList<>();
      yearlyInboundCoal.forEach((year, total) -> {
            resultVo yearlyInboundResult = new resultVo(year, total.doubleValue(), "2");
            yearlyInbound.add(yearlyInboundResult);
          });
      totalResults.add(new ResultData("year", yearlyInbound));
    }
    Map<Integer, Double> yearlyOutboundCoal = (Map<Integer, Double>)cpCoalsaveUsesList.stream().filter(usage -> ("3".equals(usage.getType()) && usage.toLocalDate().getYear() == currentYear)).collect(Collectors.groupingBy(usage -> Integer.valueOf(usage.toLocalDate().getYear()),

          Collectors.summingDouble(CpCoalsaveUses::getNumber)));
    if (!yearlyOutboundCoal.isEmpty()) {
      List<resultVo> yearlyOutbound = new ArrayList<>();
      yearlyOutboundCoal.forEach((year, total) -> {
            resultVo yearlyOutboundResult = new resultVo(year, total.doubleValue(), "3");
            yearlyOutbound.add(yearlyOutboundResult);
          });
      totalResults.add(new ResultData("year", yearlyOutbound));
    }
    Map<Month, Double> monthlyInboundCoal = (Map<Month, Double>)cpCoalsaveUsesList.stream().filter(usage -> ("2".equals(usage.getType()) && usage.toLocalDate().getYear() == currentYear && usage.toLocalDate().getMonth() == currentMonth)).collect(Collectors.groupingBy(usage -> usage.toLocalDate().getMonth(),

          Collectors.summingDouble(CpCoalsaveUses::getNumber)));
    if (!monthlyInboundCoal.isEmpty()) {
      List<resultVo> monthlyInbound = new ArrayList<>();
      monthlyInboundCoal.forEach((month, total) -> {
            resultVo monthlyInboundResult = new resultVo(Integer.valueOf(month.getValue()), total.doubleValue(), "2");
            monthlyInbound.add(monthlyInboundResult);
          });
      totalResults.add(new ResultData("month", monthlyInbound));
    }
    Map<Month, Double> monthlyOutboundCoal = (Map<Month, Double>)cpCoalsaveUsesList.stream().filter(usage -> ("3".equals(usage.getType()) && usage.toLocalDate().getYear() == currentYear && usage.toLocalDate().getMonth() == currentMonth)).collect(Collectors.groupingBy(usage -> usage.toLocalDate().getMonth(),

          Collectors.summingDouble(CpCoalsaveUses::getNumber)));
    if (!monthlyOutboundCoal.isEmpty()) {
      List<resultVo> monthlyOutbound = new ArrayList<>();
      monthlyOutboundCoal.forEach((month, total) -> {
            resultVo monthlyOutboundResult = new resultVo(Integer.valueOf(month.getValue()), total.doubleValue(), "3");
            monthlyOutbound.add(monthlyOutboundResult);
          });
      totalResults.add(new ResultData("month", monthlyOutbound));
    }
    double dailyInboundTotal = cpCoalsaveUsesList.stream().filter(usage -> ("2".equals(usage.getType()) && usage.toLocalDate().equals(today))).mapToDouble(CpCoalsaveUses::getNumber).sum();
    if (dailyInboundTotal > 0.0D) {
      List<resultVo> dailyInbound = new ArrayList<>();
      dailyInbound.add(new resultVo(Integer.valueOf(today.getDayOfMonth()), dailyInboundTotal, "2"));
      totalResults.add(new ResultData("day", dailyInbound));
    }
    double dailyOutboundTotal = cpCoalsaveUsesList.stream().filter(usage -> ("3".equals(usage.getType()) && usage.toLocalDate().equals(today))).mapToDouble(CpCoalsaveUses::getNumber).sum();
    if (dailyOutboundTotal > 0.0D) {
      List<resultVo> dailyOutbound = new ArrayList<>();
      dailyOutbound.add(new resultVo(Integer.valueOf(today.getDayOfMonth()), dailyOutboundTotal, "3"));
      totalResults.add(new ResultData("day", dailyOutbound));
    }
    return totalResults;
  }

  @PostMapping({"/listEstimate"})
  @ApiOperation(value = "统计预计", notes = "统计预计")
  private List<ResultData> listEstimate(@RequestBody statisticsVo statisticsVo1) {
    QueryWrapper<CpCoalsaveUses> queryWrapper = new QueryWrapper();
    queryWrapper.eq("yard_id", Integer.valueOf(statisticsVo1.getYardId()));
    List<CpCoalsaveUses> cpCoalsaveUsesList = this.cpCoalStatisticsService.list((Wrapper)queryWrapper);
    LocalDate today = LocalDate.now();
    int currentYear = today.getYear();
    Month currentMonth = today.getMonth();
    int currentDay = today.getDayOfMonth();
    List<ResultData> totalResults = new ArrayList<>();
    Map<Integer, Double> yearlyInboundCoal = (Map<Integer, Double>)cpCoalsaveUsesList.stream().filter(usage -> ("0".equals(usage.getType()) && usage.toLocalDate().getYear() == currentYear)).collect(Collectors.groupingBy(usage -> Integer.valueOf(usage.toLocalDate().getYear()),

          Collectors.summingDouble(CpCoalsaveUses::getNumber)));
    if (!yearlyInboundCoal.isEmpty()) {
      List<resultVo> yearlyInbound = new ArrayList<>();
      yearlyInboundCoal.forEach((year, total) -> {
            resultVo yearlyInboundResult = new resultVo(year, total.doubleValue(), "0");
            yearlyInbound.add(yearlyInboundResult);
          });
      totalResults.add(new ResultData("year", yearlyInbound));
    }
    Map<Integer, Double> yearlyOutboundCoal = (Map<Integer, Double>)cpCoalsaveUsesList.stream().filter(usage -> ("1".equals(usage.getType()) && usage.toLocalDate().getYear() == currentYear)).collect(Collectors.groupingBy(usage -> Integer.valueOf(usage.toLocalDate().getYear()),

          Collectors.summingDouble(CpCoalsaveUses::getNumber)));
    if (!yearlyOutboundCoal.isEmpty()) {
      List<resultVo> yearlyOutbound = new ArrayList<>();
      yearlyOutboundCoal.forEach((year, total) -> {
            resultVo yearlyOutboundResult = new resultVo(year, total.doubleValue(), "1");
            yearlyOutbound.add(yearlyOutboundResult);
          });
      totalResults.add(new ResultData("year", yearlyOutbound));
    }
    Map<Month, Double> monthlyInboundCoal = (Map<Month, Double>)cpCoalsaveUsesList.stream().filter(usage -> ("0".equals(usage.getType()) && usage.toLocalDate().getYear() == currentYear && usage.toLocalDate().getMonth() == currentMonth)).collect(Collectors.groupingBy(usage -> usage.toLocalDate().getMonth(),

          Collectors.summingDouble(CpCoalsaveUses::getNumber)));
    if (!monthlyInboundCoal.isEmpty()) {
      List<resultVo> monthlyInbound = new ArrayList<>();
      monthlyInboundCoal.forEach((month, total) -> {
            resultVo monthlyInboundResult = new resultVo(Integer.valueOf(month.getValue()), total.doubleValue(), "0");
            monthlyInbound.add(monthlyInboundResult);
          });
      totalResults.add(new ResultData("month", monthlyInbound));
    }
    Map<Month, Double> monthlyOutboundCoal = (Map<Month, Double>)cpCoalsaveUsesList.stream().filter(usage -> ("1".equals(usage.getType()) && usage.toLocalDate().getYear() == currentYear && usage.toLocalDate().getMonth() == currentMonth)).collect(Collectors.groupingBy(usage -> usage.toLocalDate().getMonth(),

          Collectors.summingDouble(CpCoalsaveUses::getNumber)));
    if (!monthlyOutboundCoal.isEmpty()) {
      List<resultVo> monthlyOutbound = new ArrayList<>();
      monthlyOutboundCoal.forEach((month, total) -> {
            resultVo monthlyOutboundResult = new resultVo(Integer.valueOf(month.getValue()), total.doubleValue(), "1");
            monthlyOutbound.add(monthlyOutboundResult);
          });
      totalResults.add(new ResultData("month", monthlyOutbound));
    }
    double dailyInboundTotal = cpCoalsaveUsesList.stream().filter(usage -> ("0".equals(usage.getType()) && usage.toLocalDate().equals(today))).mapToDouble(CpCoalsaveUses::getNumber).sum();
    if (dailyInboundTotal > 0.0D) {
      List<resultVo> dailyInbound = new ArrayList<>();
      dailyInbound.add(new resultVo(Integer.valueOf(today.getDayOfMonth()), dailyInboundTotal, "0"));
      totalResults.add(new ResultData("day", dailyInbound));
    }
    double dailyOutboundTotal = cpCoalsaveUsesList.stream().filter(usage -> ("1".equals(usage.getType()) && usage.toLocalDate().equals(today))).mapToDouble(CpCoalsaveUses::getNumber).sum();
    if (dailyOutboundTotal > 0.0D) {
      List<resultVo> dailyOutbound = new ArrayList<>();
      dailyOutbound.add(new resultVo(Integer.valueOf(today.getDayOfMonth()), dailyOutboundTotal, "1"));
      totalResults.add(new ResultData("day", dailyOutbound));
    }
    return totalResults;
  }

  @PostMapping({"getLineChart"})
  public List<CpCoalsaveUses> getLineChart(@RequestBody LineChartVo lineChartVo) {
    List<CpCoalsaveUses> yearlyStatistics;
    List<CpCoalsaveUses> cpCoalsaveUses;
    List<CpCoalsaveUses> monthlyStatistics;
    List<CpCoalsaveUses> filteredList;
    Calendar calendar;
    int currentYear;
    List<CpCoalsaveUses> coalsaveUses;
    List<CpCoalsaveUses> dailyStatistics;
    LocalDate today;
    LocalDate startOfWeek;
    LocalDate endOfWeek;
    List<CpCoalsaveUses> currentWeekStatistics;
    List<CpCoalsaveUses> coalsaveUses1;
    switch (lineChartVo.getChooseNum().intValue()) {
      case 1:
        yearlyStatistics = this.cpCoalStatisticsDao.getYearlyStatistics(lineChartVo.getYardId());
        cpCoalsaveUses = completeYearlyTypes(yearlyStatistics, lineChartVo.getYardId().intValue());
        Collections.sort(cpCoalsaveUses, (o1, o2) -> o1.getTime().compareTo(o2.getTime()));
        return cpCoalsaveUses;
      case 2:
        monthlyStatistics = this.cpCoalStatisticsDao.getMonthlyStatistics(lineChartVo.getYardId());
        filteredList = new ArrayList<>();
        calendar = Calendar.getInstance();
        currentYear = calendar.get(1);
        for (CpCoalsaveUses use : monthlyStatistics) {
          Calendar useCalendar = Calendar.getInstance();
          useCalendar.setTime(use.getTime());
          if (useCalendar.get(1) == currentYear)
            filteredList.add(use);
        }
        coalsaveUses = completeMonthTypes(filteredList, lineChartVo.getYardId());
        Collections.sort(coalsaveUses, (o1, o2) -> o1.getTime().compareTo(o2.getTime()));
        return coalsaveUses;
      case 3:
        dailyStatistics = this.cpCoalStatisticsDao.getDailyStatistics(lineChartVo.getYardId());
        today = LocalDate.now();
        startOfWeek = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        endOfWeek = startOfWeek.plusDays(6L);
        currentWeekStatistics = new ArrayList<>();
        for (CpCoalsaveUses use : dailyStatistics) {
          LocalDate date = use.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
          if (!date.isBefore(startOfWeek) && !date.isAfter(endOfWeek))
            currentWeekStatistics.add(use);
        }
        coalsaveUses1 = completeWeekTypes(currentWeekStatistics, lineChartVo.getYardId());
        Collections.sort(coalsaveUses1, (o1, o2) -> o1.getTime().compareTo(o2.getTime()));
        return coalsaveUses1;
    }
    return null;
  }

  public static List<CpCoalsaveUses> completeYearlyTypes(List<CpCoalsaveUses> originalList, int yardId) {
    Map<Integer, List<CpCoalsaveUses>> yearlyMap = new TreeMap<>();
    for (CpCoalsaveUses entry : originalList) {
      int year = entry.getYear();
      ((List<CpCoalsaveUses>)yearlyMap.computeIfAbsent(Integer.valueOf(year), k -> new ArrayList())).add(entry);
    }
    List<CpCoalsaveUses> completedList = new ArrayList<>(originalList);
    Set<String> allTypes = new HashSet<>(Arrays.asList(new String[] { "0", "1", "2", "3" }));
    for (Map.Entry<Integer, List<CpCoalsaveUses>> entry : yearlyMap.entrySet()) {
      int year = ((Integer)entry.getKey()).intValue();
      List<CpCoalsaveUses> yearEntries = entry.getValue();
      Set<String> existingTypes = new HashSet<>();
      for (CpCoalsaveUses use : yearEntries)
        existingTypes.add(use.getType());
      for (String type : allTypes) {
        if (!existingTypes.contains(type)) {
          Calendar calendar = Calendar.getInstance();
          calendar.set(year, 0, 1);
          calendar.set(11, 0);
          calendar.set(12, 0);
          calendar.set(13, 0);
          calendar.set(14, 0);
          CpCoalsaveUses newEntry = new CpCoalsaveUses(0, calendar.getTime(), "admin", type, 0.0D, yardId);
          completedList.add(newEntry);
        }
      }
    }
    return completedList;
  }

  public static List<CpCoalsaveUses> completeMonthTypes(List<CpCoalsaveUses> filteredList, Integer yardId) {
    Map<Integer, Set<String>> monthTypeMap = new HashMap<>();
    for (CpCoalsaveUses use : filteredList) {
      int i = use.toLocalDate().getMonthValue();
      String type = use.getType();
      ((Set<String>)monthTypeMap.computeIfAbsent(Integer.valueOf(i), k -> new HashSet())).add(type);
    }
    List<CpCoalsaveUses> completedList = new ArrayList<>(filteredList);
    for (int month = 1; month <= 12; month++) {
      Set<String> existingTypes = monthTypeMap.getOrDefault(Integer.valueOf(month), new HashSet<>());
      List<String> missingTypes = Arrays.asList(new String[] { "0", "1", "2", "3" });
      missingTypes.removeAll(existingTypes);
      LocalDate referenceDate = LocalDate.of(LocalDate.now().getYear(), month, 1);
      for (String missingType : missingTypes) {
        CpCoalsaveUses newUse = new CpCoalsaveUses();
        newUse.setId(0);
        newUse.setTime(Date.from(referenceDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
        newUse.setName("admin");
        newUse.setType(missingType);
        newUse.setNumber(0.0D);
        newUse.setYardId(yardId.intValue());
        completedList.add(newUse);
      }
    }
    return completedList;
  }

  public List<CpCoalsaveUses> completeWeekTypes(List<CpCoalsaveUses> filteredList, Integer yardId) {
    LocalDate startOfWeek = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
    LocalDate endOfWeek = startOfWeek.plusDays(6L);
    Map<LocalDate, Map<String, Boolean>> dailyTypePresence = new HashMap<>();
    for (CpCoalsaveUses use : filteredList) {
      LocalDate date = use.toLocalDate();
      if (!date.isBefore(startOfWeek) && !date.isAfter(endOfWeek))
        ((Map<String, Boolean>)dailyTypePresence.computeIfAbsent(date, k -> new HashMap<>())).put(use.getType(), Boolean.valueOf(true));
    }
    List<CpCoalsaveUses> completeList = new ArrayList<>(filteredList);
    for (LocalDate day = startOfWeek; !day.isAfter(endOfWeek); day = day.plusDays(1L)) {
      for (String type : new String[] { "0", "1", "2", "3" }) {
        if (!((Map)dailyTypePresence.getOrDefault(day, new HashMap<>())).containsKey(type)) {
          CpCoalsaveUses newUse = new CpCoalsaveUses();
          newUse.setTime(Date.from(day.atStartOfDay(ZoneId.systemDefault()).toInstant()));
          newUse.setName("admin");
          newUse.setType(type);
          newUse.setNumber(0.0D);
          newUse.setYardId(yardId.intValue());
          completeList.add(newUse);
        }
      }
    }
    return completeList;
  }
}
